package com.xique.door.biz.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.github.pagehelper.PageInfo;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.StringUtils;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.door.bean.dao.BuildingDeviceDAO;
import com.xique.door.bean.domain.AccessDevice;
import com.xique.door.bean.domain.User;
import com.xique.door.bean.domain.UserDevice;
import com.xique.door.bean.request.device.DeviceDeleteRequest;
import com.xique.door.bean.request.deviceUser.DeviceAddUserRequest;
import com.xique.door.bean.request.deviceUser.DeviceBatchUserListRequest;
import com.xique.door.bean.request.deviceUser.DeviceDeleteUserRequest;
import com.xique.door.bean.request.deviceUser.DeviceUserSelectListRequest;
import com.xique.door.bean.search.UserDeviceListSearch;
import com.xique.door.bean.search.UserDeviceSearch;
import com.xique.door.bean.transfer.UserHouseTransfer;
import com.xique.door.bean.vo.user.UserHouseVo;
import com.xique.door.bean.vo.user.UserListVo;
import com.xique.door.biz.service.IDeviceUserBizService;
import com.xique.door.command.IDeviceUserCommandService;
import com.xique.door.device.command.AccessCommandHQService;
import com.xique.door.device.freeview.constant.CommandStatus;
import com.xique.door.device.freeview.service.biz.FreeviewCommandBizService;
import com.xique.door.mapper.UserDeviceMapper;
import com.xique.door.service.IAccessDeviceService;
import com.xique.door.service.IUserDeviceService;
import com.xique.door.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Array;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author shd
 * @create 2022/1/28 14:26
 */
@Service
public class DeviceUserBizServiceImpl implements IDeviceUserBizService {

    @Autowired
    private IUserDeviceService userDeviceService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IDeviceUserBizService deviceUserBizService;

    @Autowired
    private FreeviewCommandBizService freeviewCommandBizService;

    @Autowired
    private IAccessDeviceService accessDeviceService;

    @Autowired
    private UserDeviceMapper userDeviceMapper;

    @Autowired
    private AccessCommandHQService accessCommandHQService;

    @Autowired
    private IDeviceUserCommandService deviceUserCommandService;

    @Autowired
    private UserHouseTransfer userHouseTransfer;

    @Override
    public List<UserListVo> selectAssignedDeviceUserList(DeviceUserSelectListRequest request) {
        List<UserListVo> list = userService.selectAssignedDeviceUserList(request);
        // 删除重复得数据
        // List<UserListVo> list = new ArrayList<>();
        // if (CollectionUtil.isNotEmpty(arrayList)) {
        //     list = arrayList.stream().collect(Collectors.collectingAndThen(
        //             Collectors.toCollection(() -> new TreeSet<>(
        //                     Comparator.comparing(UserListVo::getId))
        //             ), ArrayList::new)
        //     );
        // }
        //通过userid，查出用户的房屋信息
        if (list.isEmpty()) {
            return list;
        }
        List<UserHouseVo> houseBuildingAreaDaos = userHouseTransfer.transferUserListVo(list.stream().map(UserListVo::getId).collect(Collectors.toList()));
        list.forEach(e -> {
            List<UserHouseVo> userHouseVos = houseBuildingAreaDaos.stream().filter(dao -> dao.getUserId().equals(e.getId())).collect(Collectors.toList());
            e.setUserHouseVos(userHouseVos);
        });

        return list;
    }

    @Override
    public AjaxResult selectUnAssignedDeviceUserList(DeviceUserSelectListRequest request) {
        request.setParkId(SecurityUtils.getParkId());
        List<UserListVo> list = userService.selectUnAssignedDeviceUserList(request);
        if (!list.isEmpty()) {
            //通过userid，查出用户的房屋信息
            List<UserHouseVo> houseBuildingAreaDaos = userHouseTransfer.transferUserListVo(list.stream().map(UserListVo::getId).collect(Collectors.toList()));
            list.forEach(e -> {
                List<UserHouseVo> userHouseVos = houseBuildingAreaDaos.stream().filter(dao -> dao.getUserId().equals(e.getId())).collect(Collectors.toList());
                e.setUserHouseVos(userHouseVos);
            });
        }

        long total = new PageInfo(list).getTotal();
        Map<String, Object> map = new HashMap<>(2);
        map.put("list", list);
        map.put("total", total);

        return AjaxResult.success(map);
    }

    /**
     * @param request
     * @description: 下发到设备-新增用户
     * @author caogq
     * @date 2022/2/15 16:18
     */
    @Override
    public AjaxResult addDeviceUser(DeviceAddUserRequest request) {
        AccessDevice accessDevice = accessDeviceService.selectAccessDeviceById(request.getDeviceId());
        StringBuilder stringBuilder = new StringBuilder("下发成功，等待设备处理。");
        if (!StringUtils.isEmpty(request.getUserIds())) {
            //单设备下发多用户
            List<Long> userIds = Arrays.asList(request.getUserIds().split(",")).stream().map(e -> Long.parseLong(e)).collect(Collectors.toList());
            List<User> users = userService.selectUserByIds(userIds);
            List<User> needCommandUsers = new ArrayList<>();
            for (User user : users) {
                //批量下发时，跳过没有上传人脸的用户
                if (StringUtils.isEmpty(user.getFaceUrl())) {
                    stringBuilder.append("<br/> 用户【" + user.getUserName() + "】未上传人脸照片，跳过下发！");
                    continue;
                }
                needCommandUsers.add(user);
            }
            if (needCommandUsers.isEmpty()) {
                return AjaxResult.error("用户未上传图片,请上传图片后再下发");
            }
            AjaxResult result = this.addDeviceUsers(accessDevice, needCommandUsers);
            if (AjaxResult.isError(result)) {
                return result;
            }
        }
        if (request.getUserId() != null) {
            //单设备下发单用户
            User user = userService.selectUserById(request.getUserId());
//            if (StringUtils.isEmpty(user.getFaceUrl())){
//                return AjaxResult.error("用户【"+ user.getUserName()+"】未上传人脸照片！");
//            }
            AjaxResult result = this.addDeviceUser(accessDevice, user);
            if (AjaxResult.isError(result)) {
                return result;
            }
        }
        return AjaxResult.success(stringBuilder.toString());
    }

    /**
     * @param request
     * @description: 下发到设备-删除用户
     * @author caogq
     * @date 2022/2/15 16:18
     */
    @Override
    public AjaxResult removeDeviceUser(DeviceDeleteUserRequest request) {
        AccessDevice accessDevice = accessDeviceService.selectAccessDeviceById(request.getDeviceId());
        if (request.getUserId() != null) {
            //单设备删除单用户
            User user = userService.selectUserById(request.getUserId());
            AjaxResult result = this.removeDeviceUser(accessDevice, user);
            if (AjaxResult.isError(result)) {
                return result;
            }
        }
        if (!StringUtils.isEmpty(request.getUserIds())) {
            //单设备删除多用户
            List<Long> userIds = Arrays.asList(request.getUserIds().split(",")).stream().map(e -> Long.parseLong(e)).collect(Collectors.toList());
            List<User> users = userService.selectUserByIds(userIds);
            AjaxResult result = this.removeDeviceUsers(accessDevice, users);
            if (AjaxResult.isError(result)) {
                return result;
            }
        }
        return AjaxResult.success();
    }

    @Override
    public AjaxResult addDeviceUser(AccessDevice accessDevice, User user) {
        AjaxResult result = this.insertUpdateUserDeviceDomain(accessDevice, Collections.singletonList(user), CommandStatus.SEND);
        if (AjaxResult.isError(result)) {
            return result;
        }
        if (StringUtils.isEmpty(user.getFaceUrl())) {
            return result;
        }
        return deviceUserCommandService.downDevicesUsers(Collections.singletonList(accessDevice), Collections.singletonList(user));
    }

    @Override
    public AjaxResult addDeviceUsers(AccessDevice accessDevice, List<User> users) {
        AjaxResult result = this.insertUpdateUserDeviceDomain(accessDevice, users, CommandStatus.SEND);
        if (AjaxResult.isError(result)) {
            return result;
        }
        return deviceUserCommandService.downDevicesUsers(Collections.singletonList(accessDevice), users);
    }

    public int insertUserDevice(List<User> users, AccessDevice accessDevice) {
        if (users.isEmpty()) {
            return 0;
        }
        if (users.size() == 1) {
            User user = users.get(0);
            UserDevice userDevice = new UserDevice();
            userDevice.setParkId(accessDevice.getParkId());
            userDevice.setUserId(user.getId());
            userDevice.setDevSn(accessDevice.getDevSn());
            userDevice.setDeviceId(accessDevice.getId());
            userDevice.setStatus(CommandStatus.SEND);
            userDevice.setCustomId(user.getCustomId());
            int i = userDeviceService.insertUserDevice(userDevice);
            return 1;
        }
        List<UserDevice> userDevices = new ArrayList<>();
        for (User user : users) {
            UserDevice userDevice = new UserDevice();
            userDevice.setParkId(accessDevice.getParkId());
            userDevice.setUserId(user.getId());
            userDevice.setDevSn(accessDevice.getDevSn());
            userDevice.setModel(accessDevice.getModel());
            userDevice.setDeviceId(accessDevice.getId());
            userDevice.setStatus(CommandStatus.SEND);
            userDevice.setCustomId(user.getCustomId());
            userDevices.add(userDevice);
        }
        return userDeviceService.batchInsertUserDevice(userDevices);
    }

    public AjaxResult insertUpdateUserDeviceDomain(AccessDevice accessDevice, List<User> users, String status) {

        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        //2、平台新增设备用户关系
        UserDeviceSearch userDeviceSearch = new UserDeviceSearch();
        userDeviceSearch.setDeviceId(accessDevice.getId());
        userDeviceSearch.setUserIds(userIds);
        //查询出已经下发过的设备用户数据-更新状态和下发时间
        List<UserDevice> existUserDevices = userDeviceService.selectUserDeviceListBySearch(userDeviceSearch);
        List<User> needAddUsers = users;
        if (!existUserDevices.isEmpty()) {
            List<Long> existUserIds = existUserDevices.stream().map(UserDevice::getUserId).collect(Collectors.toList());
            for (UserDevice existUserDevice : existUserDevices) {
                User user = users.stream().filter(e -> e.getId().equals(existUserDevice.getUserId())).findAny().orElse(null);
                existUserDevice.setUpdateTime(new Date());
                if (StringUtils.isEmpty(accessDevice.getOnlineStatus()) || "offline".equals(accessDevice.getOnlineStatus())) {
                    existUserDevice.setStatus(CommandStatus.PENDING);
                } else {
                    if (StringUtils.isNotEmpty(user.getFaceUrl())) {
                        existUserDevice.setStatus(CommandStatus.SEND);
                    } else {
                        existUserDevice.setStatus(CommandStatus.NOFACE);
                    }
                }
            }
            userDeviceService.batchUpdateUserDevice(existUserDevices);
            //查询出未下发过的
            needAddUsers = users.stream().filter(u -> !existUserIds.contains(u.getId())).collect(Collectors.toList());
        }
        List<UserDevice> userDevices = new ArrayList<>();
        for (User user : needAddUsers) {
            UserDevice userDevice = new UserDevice();
            userDevice.setParkId(accessDevice.getParkId());
            userDevice.setUserId(user.getId());
            userDevice.setDevSn(accessDevice.getDevSn());
            userDevice.setModel(accessDevice.getModel());
            userDevice.setDeviceId(accessDevice.getId());
            if (StringUtils.isEmpty(accessDevice.getOnlineStatus()) || "offline".equals(accessDevice.getOnlineStatus())) {
                userDevice.setStatus(CommandStatus.PENDING);
            } else {
                if (StringUtils.isNotEmpty(user.getFaceUrl())) {
                    userDevice.setStatus(CommandStatus.SEND);
                } else {
                    userDevice.setStatus(CommandStatus.NOFACE);
                }
            }
            userDevice.setCustomId(user.getCustomId());
            userDevices.add(userDevice);
        }
        int i = userDeviceService.batchInsertUserDevice(userDevices);
        return i > 0 ? AjaxResult.success() : AjaxResult.error();
    }

    /**
     * @param accessDevice
     * @param user
     * @description: 单个设备删除单个用户
     * @author caogq
     * @date: 2022/2/16 19:01
     */
    @Override
    public AjaxResult removeDeviceUser(AccessDevice accessDevice, User user) {
        UserDeviceSearch search = new UserDeviceSearch();
        search.setDeviceId(accessDevice.getId());
        search.setUserId(user.getId());
        List<UserDevice> userDeviceList = userDeviceService.selectUserDeviceListBySearch(search);
        for (UserDevice existUserDevice : userDeviceList) {
            existUserDevice.setUpdateTime(new Date());
            existUserDevice.setStatus(CommandStatus.SEND);
        }
        int i = userDeviceService.batchUpdateUserDevice(userDeviceList);

        AjaxResult result = deviceUserCommandService.deleteDevicesUsers(Collections.singletonList(accessDevice), Collections.singletonList(user));
        if (AjaxResult.isError(result)) {
            return result;
        }
        return i > 0 ? AjaxResult.success() : AjaxResult.error();
    }

    /**
     * @param request
     * @description: 全量删除设备中所有用户
     * @author taojc
     * @date: 2022/8/16
     */
    @Override
    public void removeAllDeviceUsers(DeviceDeleteRequest request) {
        // 设备绑定的用户
        UserDevice search = new UserDevice();
        search.setDeviceId(request.getId());
        List<UserDevice> userDeviceList = userDeviceService.selectUserDeviceList(search);
        if(!CollectionUtils.isEmpty(userDeviceList)){
            // 删除用户
            if(userDeviceList.size()==1){
                userDeviceMapper.deleteUserDeviceById(userDeviceList.get(0).getId());

            }else{
                List<Long> ids = userDeviceList.stream().map(UserDevice::getId).collect(Collectors.toList());
                userDeviceMapper.deleteUserDeviceByDeviceIds(ids);
            }
        }
    }


    /**
     * @param accessDevice
     * @param users
     * @description: 单个设备删除多个用户
     * @author caogq
     * @date: 2022/2/16 19:01
     */
    @Override
    public AjaxResult removeDeviceUsers(AccessDevice accessDevice, List<User> users) {
        //part1 : 设备用户表更新
        UserDeviceSearch search = new UserDeviceSearch();
        search.setDeviceId(accessDevice.getId());
        search.setUserIds(users.stream().map(User::getId).collect(Collectors.toList()));
        List<UserDevice> userDeviceList = userDeviceService.selectUserDeviceListBySearch(search);
        for (UserDevice existUserDevice : userDeviceList) {
            existUserDevice.setUpdateTime(new Date());
            existUserDevice.setStatus(CommandStatus.SEND);
        }
        int i = userDeviceService.batchUpdateUserDevice(userDeviceList);

        // part 2 : 指令下发
        AjaxResult result = deviceUserCommandService.deleteDevicesUsers(Collections.singletonList(accessDevice), users);
        if (AjaxResult.isError(result)) {
            return result;
        }
        return i > 0 ? AjaxResult.success() : AjaxResult.error();
    }

    /**
     * @param request
     * @description: 全量下发设备中已有的用户
     * @author caogq
     * @date: 2022/2/16 19:49
     * @Param
     */
    @Override
    public AjaxResult addAllDeviceUser(DeviceDeleteUserRequest request) {
        AccessDevice accessDevice = accessDeviceService.selectAccessDeviceById(request.getDeviceId());
        UserDevice userDeviceSearch = new UserDevice();
        userDeviceSearch.setDeviceId(request.getDeviceId());
        List<UserDevice> userDevices = userDeviceService.selectUserDeviceList(userDeviceSearch);
        List<Long> userIds = userDevices.stream().map(UserDevice::getUserId).collect(Collectors.toList());
        List<User> users = userService.selectUserByIds(userIds);
        //过滤出需要下发的用户
        List<User> needCommandUsers = users.stream().filter(e -> StringUtils.isNotEmpty(e.getFaceUrl())).collect(Collectors.toList());
        for (UserDevice userDevice : userDevices) {
            User user = users.stream().filter(e -> e.getId().equals(userDevice.getUserId())).findAny().orElse(null);
            userDevice.setUpdateTime(new Date());
            if (StringUtils.isEmpty(accessDevice.getOnlineStatus()) || "offline".equals(accessDevice.getOnlineStatus())) {
                userDevice.setStatus(CommandStatus.PENDING);
            } else {
                if (user != null && StringUtils.isNotEmpty(user.getFaceUrl())) {
                    userDevice.setStatus(CommandStatus.SEND);
                } else {
                    userDevice.setStatus(CommandStatus.NOFACE);
                }
            }
        }
        int i = userDeviceService.batchUpdateUserDevice(userDevices);
        if (!CollectionUtils.isEmpty(needCommandUsers)) {
            deviceUserCommandService.downDevicesUsers(Collections.singletonList(accessDevice), needCommandUsers);
        }
        return i > 0 ? AjaxResult.success("指令已发出，请等待设备处理后刷新页面") : AjaxResult.error();
    }

    /**
     * @param request
     * @description: 查询所有设备的下发记录
     * @author caogq
     * @date: 2022/3/5 10:06
     * @Param
     */
    @Override
    public List<UserListVo> selectAllDevicesUserList(DeviceUserSelectListRequest request) {
        List<UserListVo> list = userService.selectAssignedDeviceUserList(request);
        //通过userid，查出用户的房屋信息
        if (list.isEmpty()) {
            return list;
        }
        List<Long> deviceIds = list.stream().distinct().map(e -> e.getDeviceId()).collect(Collectors.toList());

        List<AccessDevice> accessDevices = accessDeviceService.selectAccessDeviceByIds(deviceIds);

        List<UserHouseVo> houseBuildingAreaDaos = userHouseTransfer.transferUserListVo(list.stream().map(UserListVo::getId).collect(Collectors.toList()));
        for (UserListVo userListVo : list) {
            List<UserHouseVo> userHouseVos = houseBuildingAreaDaos.stream().filter(dao -> dao.getUserId().equals(userListVo.getId())).collect(Collectors.toList());
            userListVo.setUserHouseVos(userHouseVos);
            AccessDevice accessDevice = accessDevices.stream().filter(device -> userListVo.getDeviceId().equals(device.getId())).findAny().orElse(null);
            if (accessDevice != null) {
                userListVo.setDeviceName(accessDevice.getName());
            }
        }
        return list;
    }

    @Override
    public AjaxResult addBatchDeviceAndUser(DeviceBatchUserListRequest request) {

        if (StringUtils.isEmpty(request.getIds())) {
            return AjaxResult.error("请传入ids");
        }

        List<Long> ids = Arrays.stream(request.getIds().split(",")).map(v -> Long.parseLong(v.trim())).collect(Collectors.toList());

        UserDeviceSearch search = new UserDeviceSearch();
        search.setIds(ids);
        List<UserDevice> list = userDeviceService.selectUserDeviceListBySearch(search);

        List<Long> deviceIds = list.stream().map(UserDevice::getDeviceId).distinct().collect(Collectors.toList());
        List<AccessDevice> accessDeviceList = accessDeviceService.selectAccessDeviceByIds(deviceIds);
        Map<Long, AccessDevice> accessDeviceMap = accessDeviceList.stream().collect(Collectors.toMap(AccessDevice::getId, v -> v));

        List<Long> userIds = list.stream().map(UserDevice::getUserId).distinct().collect(Collectors.toList());
        List<User> userList = userService.selectUserByIds(userIds);
        List<User> needCommandUsers = userList.stream().filter(e -> StringUtils.isNotEmpty(e.getFaceUrl())).collect(Collectors.toList());
        Map<Long, User> userMap = needCommandUsers.stream().collect(Collectors.toMap(User::getId, v -> v));

        Map<Long, List<UserDevice>> map = list.stream().collect(Collectors.groupingBy(UserDevice::getDeviceId));

        for (Map.Entry<Long, List<UserDevice>> entry : map.entrySet()) {
            Long deviceId = entry.getKey();
            List<UserDevice> value = entry.getValue();

            List<AccessDevice> accessDevices = Collections.singletonList(accessDeviceMap.get(deviceId));
            List<User> users = new ArrayList<>();
            List<Long> needUserIds = value.stream().map(UserDevice::getUserId).collect(Collectors.toList());
            needUserIds.forEach(item -> {
                if (StringUtils.isNotNull(userMap.get(item))) {
                    users.add(userMap.get(item));
                }
            });
            deviceUserCommandService.downDevicesUsers(accessDevices, users);
        }

        return AjaxResult.success();
    }
}
